package com.sproutcat.sample;

import lombok.Getter;
import lombok.Setter;
import org.springframework.cache.support.NullValue;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;

import java.time.Duration;

/**
 * 自定义 Redis 缓存操作处理类
 *
 * @author tzg
 */
@Setter
public class CustomRedisCache extends RedisCache {

    /**
     * 缓存的自定义超时时间
     */
    private Duration ttl;
    /**
     * 空值的超时时间（默认为 5 秒）
     */
    private Duration nullTtl = Duration.ofSeconds(5);

    protected CustomRedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) {
        super(name, cacheWriter, cacheConfig);
    }

    public Duration getTtl() {
        return ttl != null ? ttl : getCacheConfiguration().getTtl();
    }

    @Override
    public void put(Object key, Object value) {
        Object cacheValue = preProcessCacheValue(value);

        if (!isAllowNullValues() && cacheValue == null) {

            throw new IllegalArgumentException(String.format(
                    "Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.",
                    getName()));
        }

        Duration meTtl = getTtl();
        if (isAllowNullValues() && value instanceof NullValue) {
            meTtl = nullTtl;
        }

        getNativeCache().put(getName(), serializeCacheKey(createCacheKey(key)), serializeCacheValue(cacheValue), meTtl);
    }

    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        Object cacheValue = preProcessCacheValue(value);

        if (!isAllowNullValues() && cacheValue == null) {
            return get(key);
        }

        Duration meTtl = getTtl();
        if (isAllowNullValues() && value instanceof NullValue) {
            meTtl = nullTtl;
        }

        byte[] result = getNativeCache().putIfAbsent(getName(), serializeCacheKey(createCacheKey(key)),
                serializeCacheValue(cacheValue), meTtl);

        if (result == null) {
            return null;
        }

        return new SimpleValueWrapper(fromStoreValue(deserializeCacheValue(result)));
    }
}
